package me.wz.util.sdbc.spring;

import me.wz.util.Assert;
import me.wz.util.exception.RTException;
import me.wz.util.sdbc.ITransaction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.Callable;

public abstract class TransactionSupport implements ITransaction {

    @Autowired(required = false)
    private PlatformTransactionManager platformTransactionManager;
    @Autowired(required = false)
    private DefaultTransactionDefinition transactionDefinition;

    private ThreadLocal<TransactionStatus> transactionStatus = new ThreadLocal<TransactionStatus>();

    public void startTransaction() {
        transactionStatus.set(getPlatformTransactionManager().getTransaction(getTransactionDefinition()));
    }
    public void commit() {
        getPlatformTransactionManager().commit(transactionStatus.get());
    }
    public void rollback() {
        getPlatformTransactionManager().rollback(transactionStatus.get());
    }
    public void close() {
        transactionStatus.remove();
    }
    public <T>T transaction(Callable<T> callable) {
        try {
            startTransaction();
            T ret = callable.call();
            commit();
            return ret;
        }
        catch(Exception e) {
            rollback();
            throw new RTException(e.getMessage(), e);
        }
        finally {
            close();
        }
    }

    protected abstract DataSource getDataSource();
    protected Connection getConnection() throws SQLException { return getDataSource().getConnection(); }


    public PlatformTransactionManager getPlatformTransactionManager() {
        if( platformTransactionManager == null ) {
            synchronized (this) {
                if( platformTransactionManager == null ) {
                    platformTransactionManager = new DataSourceTransactionManager(getDataSource());
                }
            }
        }
        return platformTransactionManager;
    }

    public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
        this.platformTransactionManager = platformTransactionManager;
    }

    public DefaultTransactionDefinition getTransactionDefinition() {
        if( transactionDefinition == null ){
            synchronized (this) {
                if( transactionDefinition == null ){
                    transactionDefinition = new DefaultTransactionDefinition();
                    transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
                    transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
                }
            }
        }
        return transactionDefinition;
    }

    public void setTransactionDefinition(DefaultTransactionDefinition transactionDefinition) {
        this.transactionDefinition = transactionDefinition;
    }
}
